import type { CAC } from "cac";

import { extname } from "node:path";

import { getStagedFiles } from "@vben/node-utils";
import { circularDepsDetect, printCircles } from "circular-dependency-scanner";

const IGNORE_DIR = [
  "dist",
  ".turbo",
  "output",
  ".cache",
  "scripts",
  "internal",
  "packages/effects/request/src/",
  "packages/@core/ui-kit/menu-ui/src/",
  "packages/@core/ui-kit/popup-ui/src/",
].join(",");

const IGNORE = [`**/{${IGNORE_DIR}}/**`];

interface CommandOptions {
  staged: boolean;
  verbose: boolean;
}

async function checkCircular({ staged, verbose }: CommandOptions) {
  const results = await circularDepsDetect({
    absolute: staged,
    cwd: process.cwd(),
    ignore: IGNORE,
  });

  if (staged) {
    let files = await getStagedFiles();

    const allowedExtensions = new Set([
      ".cjs",
      ".js",
      ".jsx",
      ".mjs",
      ".ts",
      ".tsx",
      ".vue",
    ]);

    // 过滤文件列表
    files = files.filter((file) => allowedExtensions.has(extname(file)));

    const circularFiles: string[][] = [];

    for (const file of files) {
      for (const result of results) {
        const resultFiles = result.flat();
        if (resultFiles.includes(file)) {
          circularFiles.push(result);
        }
      }
    }
    verbose && printCircles(circularFiles);
  } else {
    verbose && printCircles(results);
  }
}

function defineCheckCircularCommand(cac: CAC) {
  cac
    .command("check-circular")
    .option(
      "--staged",
      "Whether it is the staged commit mode, in which mode, if there is a circular dependency, an alarm will be given.",
    )
    .usage(`Analysis of project circular dependencies.`)
    .action(async ({ staged }) => {
      await checkCircular({ staged, verbose: true });
    });
}

export { defineCheckCircularCommand };
